<?php
ini_set('date.timezone','Asia/Shanghai');
//error_reporting(E_ERROR);

error_reporting(E_ALL);
ini_set('display_errors', '1');

//将出错信息输出到一个文本文件
ini_set('error_log', dirname(__FILE__) . '/Logs/error_log.txt');

require_once "lib/WxPay.Api.php";
require_once 'lib/WxPay.Notify.php';
require_once 'log.php';

//初始化日志
$logHandler= new CLogFileHandler("Logs/".date('Y-m-d').'.log');
$log = Log::Init($logHandler, 15);

class PayNotifyCallBack extends WxPayNotify
{
	//查询订单
	public function Queryorder($transaction_id)
	{
		$input = new WxPayOrderQuery();
		$input->SetTransaction_id($transaction_id);
		$result = WxPayApi::orderQuery($input);
		Log::DEBUG("query:" . json_encode($result));
		if(array_key_exists("return_code", $result) && array_key_exists("result_code", $result) && $result["return_code"] == "SUCCESS" && $result["result_code"] == "SUCCESS") {
		    Log::DEBUG('Query:SUCCESS');
			return true;
		}
		return false;
	}
	
	//重写回调处理函数
	public function NotifyProcess($data, &$msg)
	{
		Log::DEBUG("call back:" . json_encode($data));
		$notfiyOutput = array();
		
		if(!array_key_exists("transaction_id", $data)){
			$msg = "输入参数不正确";
			Log::DEBUG($msg);
			return false;
		}
		//查询订单，判断订单真实性
		if(!$this->Queryorder($data["transaction_id"])){
			$msg = "订单查询失败";
            Log::DEBUG($msg);
			return false;
		}
		
		require_once 'lib/DB.php';
		// step1 修改数据库状态，
        //[2017-04-12 17:36:04][debug] call back:{"appid":"wxc41cd197a1e2a6da","bank_type":"CFT","cash_fee":"10","fee_type":"CNY","is_subscribe":"Y","mch_id":"1447838802","nonce_str":"wkkmcqxpldnf9tovyigis2chwtoap9x6","openid":"oRjbywrHJHPY3EFJjcU38M6GDmm8","out_trade_no":"120170412173555565317","result_code":"SUCCESS","return_code":"SUCCESS","sign":"2F055BE87317326A4B2AA41D6CB930D7","time_end":"20170412173603","total_fee":"10","trade_type":"JSAPI","transaction_id":"4005632001201704126756017248"}
        $trade_no = $data['out_trade_no'];
        $db = new DB();
        $map = array(
            'trade_no' => $data['out_trade_no']
        );
        $trade = $db->getOne('appc_trade',$map);
        if ($trade['pay_status'] == 1) {
            Log::DEBUG('call back:SUCCESS-2');
            return true;
        }
        $data = array(
            'callback_charge' => json_encode($data),
            'pay_status' => 1 // 支付成功状态
        );
        $rst = $db->update('appc_trade',$map, $data);
        if ($rst) {
            $game = $db->getOne('appc_game',"id=".$trade['game_id']);
            $callback_rst = array();
            $mode = 0;
            if ($game['gid'] == '10004') { // 空中网回调
                $callback_rst = notifyKZW($trade,$game);
                $mode = 1;
            } else { // 纷至娱乐等统一回调
                if (!empty($game['reurl'])) { // 只有在回调接口不为空的时候，才进行回调
                    $callback_rst = notifyH5Game($trade, $game);
                }
            }
            if (!empty($callback_rst)) {
                if(!$callback_rst['result']) { // 回调不成功
                    if (!empty($callback_rst['url'])) { // 回调不成功，并且拼装了参数
                        // 回调未成功。进入Task表，等待处理。
                        $data = array(
                            'trade_no' =>$trade_no,
                            'callback_url' => $callback_rst['url'],
                            'callback_status' => 0,
                            'callback_time' => date('Y-m-d H:i:s'),
                            'callback_mode' => $mode
                        );
                        $bool = $db->insert('appc_callback_task',$data);
                        Log::DEBUG('query:'.$db->getError());
                        Log::DEBUG('Insert Task:'.$trade_no);
                    }
                } else { // 回调成功，修改相应状态
                    $data = array(
                        'callback_status' => 1
                    );
                    $db->update('appc_trade',$map, $data);
                }
            }
    
            // 分发支付结果给渠道
            $channel = $db->getOne('appc_player', 'id='.$trade['player_id'], 'channel_id');
            if (!empty($channel)) {
                // 查询渠道扣量比例
                $map = array('channel_id'=>$channel['channel_id'], 'type'=>3, 'open'=>1);  // 这里直接写死为3
                $kou = $db->getOne('appc_channel_kou', $map);
                $kou = empty($kou) ? array('max_v'=>0,'bi'=>0) : $kou;
        
                $day = date('Y-m-d 00:00:00');
                $map = array('channel_id'=>$channel['channel_id'], 'type'=>3, 'day'=>$day);
                $one = $db->getOne('appc_channel_data', $map);
                if (empty($one)) { // 插入
                    $data = array(
                        'channel_id'=>$channel['channel_id'], 'type'=>3,'day'=>$day,
                        'value' => $trade['pay'],
                        'show_value' => getKouStep(0,0,$kou['max_v'],$kou['bi'], $trade['pay'])
                    );
                    $bool = $db->insert('appc_channel_data',$data);
                    if (!$bool) {Log::ERROR('Insert Channel data error, TradeId:'.$trade_no);}
                } else { // 更新
                    $data = array(
                        'value' => array('exp','value+'.$trade['pay']),
                        'show_value' => array('exp', 'show_value+'.getKouStep($one['value'], $one['show_value'], $kou['max_v'],$kou['bi'],$trade['pay']))
                    );
                    $bool = $db->update('appc_channel_data','id='.$one['id'], $data);
                    if (!$bool) {Log::ERROR('Update Channel data error, TradeId:'.$trade_no);}
                }
        
            }
            Log::DEBUG('call back:SUCCESS');
            return true;
        }  else {
            Log::DEBUG('call back:Update Database Error;'.$db->getError());
            return true;
        }
        
	}
}

Log::DEBUG("begin notify");
$notify = new PayNotifyCallBack();
$notify->Handle(false);


/**
 * 统一接口回调
 */
function notifyH5Game($trade, $game){
    $url = $game['reurl'];
    $trade_no = $trade['trade_no']; // 订单号
    $amount = $trade['pay'];
    $g_id = $trade['game_id']; // 游戏ID
    $gparams = urlencode($trade['callback_parms']);
    $key= $game['appkey'];
    $sign = md5("trade_no=$trade_no&amount=$amount&g_id=$g_id&gparams=$gparams&key=$key");
    Log::DEBUG('game----md5:'."trade_no=$trade_no&amount=$amount&g_id=$g_id&gparams=$gparams&key=$key".'    -----   md5:'.$sign);
    $get_url = $url."?trade_no=$trade_no&amount=$amount&g_id=$g_id&gparams=$gparams&sign=$sign";
    $rst = array(
        'result' => false,
        'url' => $get_url
    );
    try{
        $content = file_get_contents($get_url);
        $tmp = json_decode($content, true);
        if (isset($tmp['status']) && strtolower($tmp['status']) == 'success') {
            $rst['result'] = true;
        }
        Log::DEBUG('call back game:'.$content);
        $rst['info'] = $content;
    } catch (Exception $exception) {
        Log::DEBUG('call back game exception: '.$exception->getMessage());
        $rst['info'] = $exception->getMessage();
    }
    return $rst;
}


/**
 * 空中网回调方法
 */
function notifyKZW ($trade,$game){
    $rst = array( // 返回值
        'result' => false,
        'url' => ''
    );
    try{
        $params = getParams($game['extra_key']);
        $callback_params = json_decode($trade['callback_parms'], true);
        $debug = isset($params['debug'])? (int) $params['debug'] : 0; // Int 是否调试链接 0-测试;1-正式
        $url = $game['reurl'];
    
        $appkey = $game['appkey'];
        $ly = 'wozan';
        $uid = $trade['player_id'];
        $uname = $callback_params['username'];
        $serverId = $callback_params['serverid'];
        $ptime = date('Y-m-d H:i:s');
        $orderno = $trade['trade_no']; // 订单号
        $price = round($trade['pay']/100);
        $num = $callback_params['ybnum'];
        $yuanoritem = $callback_params['yborItem'];
        $itemId = $callback_params['itemId'];
        $itemName = $callback_params['itemName'];
        $itemNum = $callback_params['itemNum'];
        $extraparam = $callback_params['extraparam'];
        $pay_key = $params['paykey'];
        
        //示例: md5 (appkey+ly+uid+uname+serverId+ptime+orderno+price+num+yuanoritem+itemId+itemName+itemNum+extraparam+ PAY_KEY)
        $sign_val = urldecode($appkey.$ly.$uid.$uname.$serverId.$ptime.$orderno.$price.'.00'.$num.$yuanoritem.$itemId.$itemName.$itemNum.$extraparam.$pay_key);
        $sign = md5($sign_val);
        
        Log::DEBUG('game--kzw--md5:'.$sign_val.'    -----   md5:'.$sign);
        
        $param_arr = array ('appkey'=>$appkey,'ly'=>$ly,'uid'=>$uid,'uname'=>$uname,'serverId'=>$serverId,'ptime'=>$ptime,
            'orderno'=>$orderno, 'price' => $price, 'num' =>$num, 'yuanoritem'=>$yuanoritem, 'itemId'=>$itemId,
            'itemName'=>$itemName, 'itemNum'=>$itemNum, 'extraparam' =>$extraparam, 'debug'=>$debug,
            'sign'=>$sign);
        
        Log::DEBUG('game-kzw-opts'.json_encode($param_arr));
        $param = json_encode($param_arr);
        $key = base64_encode($param);
        $get_url = $url.'/'.$key;
//        $get_url = $url.$ly.'/'.$key;
        $rst['url'] = $get_url;
        $content = file_get_contents($get_url);
        $tmp = json_decode($content, true);
        if (isset($tmp['state']) && $tmp['state']) {
            $rst['result'] = true;
        }
        Log::DEBUG('call back kzw game:'.$content);
        $rst['info'] = $content;
    }catch (Exception $exception) {
        Log::DEBUG('call back game exception: '.$exception->getMessage());
        $rst['info'] = $exception->getMessage();
    }
    return $rst;
}


function getParams($str){
    $rst = array();
    $tmp = explode('&',$str);
    foreach ($tmp as $item) {
        $tmp1 = explode('=',$item);
        if (count($tmp1) == 2 && !empty($tmp1[0])) {
            $rst[$tmp1[0]] = $tmp1[1];
        }
    }
    return $rst;
}


/**
 * @param $true 真实量
 * @param $show 显示量
 * @param $max_v 扣量临界值
 * @param $bi 扣量比例
 * @param $step 自增值
 */
function getKouStep ($true, $show, $max_v,$bi, $step=1){
    if (empty($bi)) return $step; // 如果比为0，则代表不扣量
    if (($true+$step) <= $max_v) {return $step;}
    $bi = $bi/1000;
    $idend = $true ? $true : 1 ;
    $true_bi = ($true - $show ) / $idend;
    if ($true_bi<$bi) { // 直接扣，没的说
        return  $step-floor($step * $bi);
    }
    return $step;
}